#ifndef PREF_FAVORITE_H_
#define PREF_FAVORITE_H_

#include "../favorite.h"
#include "../widgets.h"
#include "p_widgets.h"

namespace gpyp {
namespace pref {

class Rule : public Gtk::VBox {
private:
  class PresetMenu : public Gtk::Menu {
  private:
    struct Preset : boost::noncopyable {
      Rule         &rule_;

      Gtk::MenuItem menu_item_;
      Glib::ustring word_;

      inline void on_activate() {
        rule_.word_.set_text(word_);
      }

      inline Preset(Rule                &rule,
                    const Glib::ustring &label,
                    const Glib::ustring &word) :
        rule_     (rule),
        menu_item_(label),
        word_     (word)
      {
        menu_item_.signal_activate()
          .connect(sigc::mem_fun(*this, &Preset::on_activate));
      }
    };

    Preset        bandwidth_;
    Gtk::MenuItem mi_ypinfo_;
    Gtk::Menu     menu_ypinfo_;
    Preset        ypinfo_general_;
    Preset        ypinfo_index_txt_;
    Preset        ypinfo_misc_;

  public:
    inline PresetMenu(Rule &rule) :
      bandwidth_       (rule, _("Bandwidth check"),
                        FavoriteCollection::PRESET_BANDWIDTH),
      mi_ypinfo_       (_("YP info")),
      ypinfo_general_  (rule, _("General"),
                        FavoriteCollection::PRESET_YPINFO_GENERAL),
      ypinfo_index_txt_(rule, _("index.txt(pcraw)"),
                        FavoriteCollection::PRESET_YPINFO_INDEX_TXT),
      ypinfo_misc_     (rule, _("Miscellaneous"),
                        FavoriteCollection::PRESET_YPINFO_MISC)
    {
      menu_ypinfo_.append(ypinfo_general_.menu_item_);
      menu_ypinfo_.append(ypinfo_index_txt_.menu_item_);
      menu_ypinfo_.append(ypinfo_misc_.menu_item_);
      mi_ypinfo_.set_submenu(menu_ypinfo_);
      append(bandwidth_.menu_item_);
      append(mi_ypinfo_);
      show_all();
    }
  };

private:
  Application     &app_;
  Gtk::Window     &parent_;

  Gtk::Entry       word_;
  Gtk::CheckButton case_sensitive_;
  Gtk::CheckButton invert_;
  Gtk::CheckButton target_name_;
  Gtk::CheckButton target_genre_;
  Gtk::CheckButton target_desc_;
  Gtk::CheckButton target_comment_;
  Gtk::CheckButton target_track_;
  Gtk::CheckButton target_contact_;
  Gtk::CheckButton target_ypname_;
  Gtk::CheckButton target_type_;
  Gtk::CheckButton target_id_;
  Gtk::CheckButton target_tip_;

  PresetMenu       preset_menu_;

  RefRule          rule_;
  sigc::connection conn_word_changed_;

  void word_on_changed();
  void word_edit_on_clicked();
  void escape_on_clicked();
  void preset_on_clicked();

public:
  void set(RefRule rule);
  void unset();

  Rule(Application &app, Gtk::Window &parent);
  virtual ~Rule();
};

class RuleCollection : public Gtk::VBox {
private:
  class Selector : public SelectorListView<gpyp::Favorite> {
  protected:
    virtual void on_cell_data(Gtk::CellRendererText *cell,
                              const Gtk::TreeIter   &iter);

  public:
    inline void set(RefFavorite favorite) {
      SelectorListView<gpyp::Favorite>::set(favorite);
      select_first();
    }
    inline void unset() {
      SelectorListView<gpyp::Favorite>::set(RefFavorite());
    }

    Selector();
  };

private:
  Selector         selector_;
  Rule             rule_;
  Gtk::CheckButton or_;
  Gtk::SpinButton  age_min_;
  Gtk::SpinButton  age_max_;

  RefFavorite      favorite_;

protected:
  virtual void on_selected(RefRule rule);

public:
  void set(RefFavorite favorite);
  void unset();

  RuleCollection(Application &app, Gtk::Window &parent);
};

class Favorite : public Gtk::VBox {
private:
  class SortCombo : public Gtk::ComboBox {
  private:
    Gtk::TreeModelColumnRecord          columns_;
    Gtk::TreeModelColumn<Glib::ustring> column_name_;
    Gtk::TreeModelColumn<ChSort>        column_value_;
    Glib::RefPtr<Gtk::ListStore>        store_;

    Gtk::TreeIter      iter_none_;
    Gtk::TreeIter      iter_top_;
    Gtk::TreeIter      iter_middle_;
    Gtk::TreeIter      iter_bottom_;

    RefAttributeChSort attr_;
    sigc::connection   conn_attr_changed_;

    inline Gtk::TreeIter append(const Glib::ustring &name, ChSort value) {
      Gtk::TreeIter iter = store_->append();
      Gtk::TreeRow  row  = *iter;
      row[column_name_]  = name;
      row[column_value_] = value;
      return iter;
    }

  protected:
    inline virtual void attr_on_changed() {
      switch(*attr_) {
      case CHSORT_TOP:    set_active(iter_top_);    break;
      case CHSORT_MIDDLE: set_active(iter_middle_); break;
      case CHSORT_BOTTOM: set_active(iter_bottom_); break;
      default:            set_active(iter_none_);   break;
      }
    }
    inline virtual void on_changed() {
      if (attr_) {
        conn_attr_changed_.block();
        Gtk::TreeIter iter = get_active();
        attr_ = iter ? iter->get_value(column_value_) : CHSORT_NONE;
        conn_attr_changed_.unblock();
      }
    }

  public:
    inline void set(RefAttributeChSort attr) {
      unset();
      attr_ = attr;
      attr_on_changed();
      conn_attr_changed_ = attr_->signal_changed()
        .connect(sigc::mem_fun(*this, &SortCombo::attr_on_changed));
    }
    inline void unset() {
      conn_attr_changed_.disconnect();
      attr_.reset();
    }

    inline SortCombo() {
      columns_.add(column_name_);
      columns_.add(column_value_);
      store_ = Gtk::ListStore::create(columns_);

      iter_none_   = append(_("None"),   CHSORT_NONE);
      iter_top_    = append(_("Top"),    CHSORT_TOP);
      iter_middle_ = append(_("Middle"), CHSORT_MIDDLE);
      iter_bottom_ = append(_("Bottom"), CHSORT_BOTTOM);

      set_model(store_);
      pack_start(column_name_);
    }
  };

private:
  Gtk::Entry       name_;
  Gtk::CheckButton enable_;
  Gtk::CheckButton filter_;

  RuleCollection   rules_;

  ColorBox         bgcolor_;
  ColorBox         fgcolor_;
  Gtk::Entry       font_;
  SortCombo        sort_;
  TriCheckButton   ng_;
  TriCheckButton   auto_play_;
  TriCheckButton   auto_record_;
  TriCheckButton   notify_new_;
  TriCheckButton   notify_change_;
  SoundBox         notify_sound_;

  RefFavorite      favorite_;

  void select_font_on_clicked();

public:
  void set(RefFavorite favorite);
  void unset();

  Favorite(Application &app,
           Gtk::Window &parent,
           RefFavorite  favorite = RefFavorite());
};

class FavoriteCollection : public Gtk::VBox {
private:
  class Selector : public SelectorListView<gpyp::FavoriteCollection> {
  protected:
    virtual void on_cell_data(Gtk::CellRendererText *cell,
                              const Gtk::TreeIter   &iter);

  public:
    Selector(Application &app);
  };

private:
  Application &app_;
  Selector     selector_;
  Favorite     favorite_;

  void apply_on_clicked();

public:
  inline void select(RefFavorite favorite) {
    selector_.select(favorite);
  }

  FavoriteCollection(Application &app, Gtk::Window &parent);
};

}/*pref*/
}/*gpyp*/

#endif/*PREF_FAVORITE_H_*/
